﻿
#region Using Directives.

using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Windows.Forms;
using System.Xml.Linq;
using RWXMLEdit.Common;

#endregion

namespace RWXMLEdit.Client.Forms
{
    public partial class FormEditUserValues : Form
    {
        #region Fields.

        private XDocument _xDoc;
        private readonly Dictionary<int, double[]> _savedValues = new Dictionary<int, double[]>();
        private readonly string _railWorksPath = string.Empty;
        private readonly RwMatrix _matrix = new RwMatrix();
        private int _index = -1;

        #endregion

        #region Constructors.

        public FormEditUserValues(XDocument xdoc, string railworkspath)
        {
            InitializeComponent();
            
            _xDoc = xdoc;

            if (Directory.Exists(railworkspath))
            {
                _railWorksPath = Path.Combine(railworkspath, "Source");
            }
            else
            {
                btnAddChildren.Enabled = false;
            }
        }

        #endregion

        #region Properties.

        public XDocument GetXDocument
        {
            get { return _xDoc; }
        }

        #endregion

        #region Events.

        private void FormEditUserValuesLoad(object sender, EventArgs e)
        {
            Init();
        }

        private void BtnUpdateClick(object sender, EventArgs e)
        {
            btnUpdate.Enabled = false;

            grbMain.Enabled = false;

            if (_index >= 0)
            {
                _savedValues[_index] = _matrix.GetMatrix(); //GetMatrix();
            }

            foreach (KeyValuePair<int, double[]> savedValue in _savedValues)
            {
                string[] formatedValues = Functions.FormatValues(savedValue.Value);

                SetValues(savedValue.Key, formatedValues);
            }
        }

        private void btnNew_Click(object sender, EventArgs e)
        {
            List<string> userValues = GetUserValuesFromCombo();

            FormAddChild frm = new FormAddChild(_railWorksPath, userValues);

            if (frm.ShowDialog(this) == DialogResult.OK)
            {
                XElement newChild = frm.GetXElement;

                if (newChild != null)
                {
                    XElement doc = XElement.Load(_xDoc.CreateReader());

                    XElement element = (from x in doc.DescendantsAndSelf()
                                        where (string)x.Attribute("name") == "Children"
                                        select x).SingleOrDefault();

                    if (element != null)
                    {
                        var xElement = element.Element("__Indexed__cEntityContainerBlueprint-sChild");
                        if (xElement != null)
                        {
                            var xElement1 = xElement.Element("Element");
                            if (xElement1 != null)
                            {
                                var xElement2 = xElement1.Element("Value");
                                if (xElement2 != null) xElement2.Add(newChild);
                            }
                        }
                    }

                    _xDoc = XDocument.Load(doc.CreateReader(), LoadOptions.PreserveWhitespace);

                    RefreshValues(frm.GetNewName);
                }
            }
        }

        private void btnRemove_Click(object sender, EventArgs e)
        {
            string value = cboUserValues.SelectedItem.ToString();

            int index = cboUserValues.SelectedIndex;

            if (!string.IsNullOrEmpty(value))
            {
                string message = string.Format("Are you sure that you want to delete the ChildName attribute: {0}?", value);

                if (MessageBox.Show(this, message, @"RailWorks XML Editor Message", MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.Yes)
                {
                    RemoveElement(value);

                    RefreshValues(string.Empty);

                    _savedValues.Remove(index);
                }
            }
        }

        private void cboUserValues_SelectedIndexChanged(object sender, EventArgs e)
        {
            var tmp = new double[16];

            if (_index >= 0)
            {
                _savedValues[_index] = _matrix.GetMatrix(); //GetMatrix();
            }

            if (cboUserValues.Items.Count > 0)
            {
                _index = cboUserValues.SelectedIndex;

                if (_savedValues.ContainsKey(_index))
                {
                    _savedValues.TryGetValue(_index, out tmp);

                    _matrix.SetMatrix(tmp); //SetMatrix(tmp);
                }
                else
                {
                    GetValues(_index);

                    _savedValues.Add(_index, _matrix.GetMatrix()); //GetMatrix());
                }

                ShowValues();

                grbMain.Text = string.Format("Edit {0}", cboUserValues.SelectedItem);
            }
        }

        private void nudXValue_ValueChanged(object sender, EventArgs e)
        {
            _matrix.SetXTranslation((double)nudXValue.Value);
            lblShowValues.Text = Functions.BuildResultString(_matrix.GetMatrix()); //GetMatrix());
        }

        private void nudXRotation_ValueChanged(object sender, EventArgs e)
        {
            _matrix.SetXRotation((double)nudXRotation.Value);
            lblShowValues.Text = Functions.BuildResultString(_matrix.GetMatrix());//GetMatrix());
        }

        private void nudYValue_ValueChanged(object sender, EventArgs e)
        {
            _matrix.SetYTranslation((double)nudYValue.Value);
            lblShowValues.Text = Functions.BuildResultString(_matrix.GetMatrix());//GetMatrix());
        }

        private void nudYRotation_ValueChanged(object sender, EventArgs e)
        {
            _matrix.SetYRotation((double)nudYRotation.Value);
            lblShowValues.Text = Functions.BuildResultString(_matrix.GetMatrix());//GetMatrix());
        }

        private void nudZValue_ValueChanged(object sender, EventArgs e)
        {
            _matrix.SetZTranslation((double)nudZValue.Value);
            lblShowValues.Text = Functions.BuildResultString(_matrix.GetMatrix());//GetMatrix());
        }

        private void nudZRotation_ValueChanged(object sender, EventArgs e)
        {
            _matrix.SetZRotation((double)nudZRotation.Value);
            lblShowValues.Text = Functions.BuildResultString(_matrix.GetMatrix());//GetMatrix());
        }

        //private void nudXValue_Click(object sender, EventArgs e)
        //{
        //    if (!btnUpdate.Enabled)
        //        btnUpdate.Enabled = true;
        //}

        //private void nudXRotation_Click(object sender, EventArgs e)
        //{
        //    if (!btnUpdate.Enabled)
        //        btnUpdate.Enabled = true;
        //}

        //private void nudYValue_Click(object sender, EventArgs e)
        //{
        //    if (!btnUpdate.Enabled)
        //        btnUpdate.Enabled = true;
        //}

        //private void nudYRotation_Click(object sender, EventArgs e)
        //{
        //    if (!btnUpdate.Enabled)
        //        btnUpdate.Enabled = true;
        //}

        //private void nudZValue_Click(object sender, EventArgs e)
        //{
        //    if (!btnUpdate.Enabled)
        //        btnUpdate.Enabled = true;
        //}

        //private void nudZRotation_Click(object sender, EventArgs e)
        //{
        //    if (!btnUpdate.Enabled)
        //        btnUpdate.Enabled = true;
        //}

        #endregion

        #region Private Methods.

        private void Init()
        {
            Text = @"Edit User Defined Attributes";

            int count = GetChildNames();

            if(count > 0)
            {
                cboUserValues.SelectedIndex = 0;

                grbUserValues.Text = string.Format("User Defined Attribute(s) [ {0} ]", count);
            }
            else
            {
                AddDefaultValues();

                btnUpdate.Enabled = false;

                btnRemove.Enabled = false;

                cboUserValues.Enabled = false;

                lblUserDefinedValues.Enabled = false;

                grbUserValues.Text = @"There are no user defined attributes";
            }
        }

        private void ShowValues()
        {
            double xValue = Functions.CheckValue(_matrix.GetXTranslation(), -999, 999);
            double yValue = Functions.CheckValue(_matrix.GetYTranslation(), -999, 999);
            double zValue = Functions.CheckValue(_matrix.GetZTranslation(), -999, 999);

            nudXValue.Value = (decimal)xValue;
            nudXRotation.Value = (decimal)_matrix.GetXRotation();

            nudYValue.Value = (decimal)yValue;
            nudYRotation.Value = (decimal)_matrix.GetYRotation();

            nudZValue.Value = (decimal)zValue;
            nudZRotation.Value = (decimal)_matrix.GetZRotation();

            lblShowValues.Text = Functions.BuildResultString(_matrix.GetMatrix());//GetMatrix());
        }

        private void RefreshValues(string newname)
        {
            int count = GetChildNames();
            int index = 0;

            if (count > 0)
            {
                if(!string.IsNullOrEmpty(newname))
                {
                    index = cboUserValues.Items.IndexOf(newname);
                }

                cboUserValues.SelectedIndex = index;

                grbUserValues.Text = string.Format("User Defined Attribute(s) [ {0} ]", count);

                cboUserValues.Enabled = true;

                btnUpdate.Enabled = true;

                btnRemove.Enabled = true;

                _index = index;
            }
            else
            {
                btnRemove.Enabled = false;

                cboUserValues.Enabled = false;

                _index = -1;
            }
        }

        private int GetChildNames()
        {
            XElement doc = XElement.Load(_xDoc.CreateReader());

            XElement element = (from x in doc.DescendantsAndSelf()
                                where (string)x.Attribute("name") == "Children"
                                select x).SingleOrDefault();

            if(element != null)
            {
                IEnumerable<XElement> list = (from x in element.DescendantsAndSelf()
                                              where (string) x.Attribute("name") == "ChildName"
                                              select x).Distinct().ToList();

                if(list.Any())
                {
                    cboUserValues.Items.Clear();

                    foreach (var xElement in list)
                    {
                        var xElement1 = xElement.Element("cDeltaString");
                        if (xElement1 != null)
                        {
                            var element1 = xElement1.Element("Element");
                            if (element1 != null)
                            {
                                var xElement2 = element1.Element("Value");
                                if (xElement2 != null)
                                    cboUserValues.Items.Add(
                                        xElement2.Value);
                            }
                        }
                    }
                    
                    return list.Count();
                }
            }

            return 0;
        }

        private void RemoveElement(string value)
        {
            XElement doc = XElement.Load(_xDoc.CreateReader());

            XElement element = (from x in doc.DescendantsAndSelf()
                                where (string)x.Attribute("name") == "Children"
                                select x).SingleOrDefault();

            if (element != null)
            {
                IEnumerable<XElement> list = (from x in element.DescendantsAndSelf("cEntityContainerBlueprint-sChild")
                                              select x).Distinct().ToList();

                foreach (XElement xElement in from xElement in list let xElement1 = xElement.Element("Element") 
                                              where xElement1 != null let xElement2 = xElement1.Element("Value") 
                                              where xElement2 != null let xElement3 = xElement2.Element("Attribute") 
                                              where xElement3 != null let xElement4 = xElement3.Element("cDeltaString") 
                                              where xElement4 != null let xElement5 = xElement4.Element("Element") 
                                              where xElement5 != null let element1 = xElement5.Element("Value") 
                                              where element1 != null && element1.Value == value select xElement)
                {
                    xElement.Remove();

                    _xDoc = XDocument.Load(doc.CreateReader(), LoadOptions.PreserveWhitespace);
                }
            }
        }

        private void GetValues(int index)
        {
            double[] values = new double[16];

            XElement doc = XElement.Load(_xDoc.CreateReader());

            XElement element = (from x in doc.DescendantsAndSelf()
                                where (string)x.Attribute("name") == "Children"
                                select x).SingleOrDefault();

            if (element != null)
            {
                IEnumerable<XElement> list = (from x in element.DescendantsAndSelf()
                                              where (string)x.Attribute("name") == "Matrix"
                                              select x).Distinct().ToList();

                if (list.Any())
                {
                    XElement tmp = list.ElementAt(index);

                    IEnumerable<XElement> listFloat32 = tmp.Descendants("sFloat32").ToList();

                    if (!listFloat32.Any())
                    {
                        Functions.AddSFloat32Tags(ref tmp);

                        listFloat32 = tmp.Descendants("sFloat32").ToList();

                        _xDoc = XDocument.Load(doc.CreateReader(), LoadOptions.PreserveWhitespace);
                    }

                    int i = 0;

                    foreach (var xElement in listFloat32)
                    {
                        if (xElement != null)
                        {
                            var xElement1 = xElement.Element("Element");
                            if (xElement1 != null)
                            {
                                var element1 = xElement1.Element("Value");
                                if (element1 != null)
                                {
                                    values[i] = Convert.ToDouble(element1.Value, CultureInfo.InvariantCulture.NumberFormat);
                                }
                            }
                        }

                        i++;
                    }

                    _matrix.SetMatrix(values);//SetMatrix(values);
                }
            }
        }

        private void SetValues(int index, string[] values)
        {
            XElement doc = XElement.Load(_xDoc.CreateReader());

            XElement element = (from x in doc.DescendantsAndSelf()
                                where (string)x.Attribute("name") == "Children"
                                select x).SingleOrDefault();

            if (element != null)
            {
                {
                    IEnumerable<XElement> list = (from x in element.DescendantsAndSelf()
                                                  where (string) x.Attribute("name") == "Matrix"
                                                  select x).Distinct().ToList();

                    if (list.Any())
                    {
                        XElement tmp = list.ElementAt(index);
                        IEnumerable<XElement> listFloat32 = tmp.Descendants("sFloat32").ToList();

                        int i = 0;

                        foreach (var xElement in listFloat32)
                        {
                            if (xElement != null)
                            {
                                var xElement1 = xElement.Element("Element");
                                if (xElement1 != null)
                                {
                                    var element1 = xElement1.Element("Value");
                                    if (element1 != null)
                                    {
                                        element1.Value = values[i];
                                    }
                                }
                            }

                            i++;
                        }
                    }
                }

                _xDoc = XDocument.Load(doc.CreateReader(), LoadOptions.PreserveWhitespace);
            }
        }

        private List<string> GetUserValuesFromCombo()
        {
            List<string> retValue = new List<string>();

            foreach (object cbi in cboUserValues.Items)
            {
                retValue.Add((string)cbi);
            }

            return retValue;
        }

        private void AddDefaultValues()
        {
            _matrix.SetMatrix(Functions.GetDefaultDoubleValues()); //SetMatrix(Functions.GetDefaultDoubleValues());
        }

        #endregion        

    }
}

